package com.mrd.gtimp.business.service;

import static com.mrd.gtimp.business.action.BusinessAction.KEY_paymentURL;
import static com.mrd.gtimp.business.action.BusinessAction.KEY_request_result;
import static com.mrd.gtimp.business.action.BusinessAction.KEY_request_result_success;

import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mrd.base.BaseBiz;
import com.mrd.constant.BaseTypeConstant;
import com.mrd.constant.MsgConstants;
import com.mrd.constant.SystemConstants;
import com.mrd.evaluate.entity.Evaluation;
import com.mrd.evaluate.service.EvaluationBiz;
import com.mrd.exception.FeeException;
import com.mrd.exception.QueryException;
import com.mrd.exception.SaveException;
import com.mrd.framework.config.web.json.Result;
import com.mrd.framework.ui.Jqgrid;
import com.mrd.framework.ui.filter.Filter;
import com.mrd.framework.ui.filter.SearchRule;
import com.mrd.framework.ui.filter.SearchRuleOption;
import com.mrd.framework.utils.HttpUtils;
import com.mrd.framework.utils.SpringUtils;
import com.mrd.gtimp.base.entity.Company;
import com.mrd.gtimp.base.entity.User;
import com.mrd.gtimp.base.repository.UserDao;
import com.mrd.gtimp.base.service.CompanyBiz;
import com.mrd.gtimp.business.action.DeclarationAction;
import com.mrd.gtimp.business.entity.BaseBusiness;
import com.mrd.gtimp.business.entity.Commodity;
import com.mrd.gtimp.business.entity.ContractTerms;
import com.mrd.gtimp.business.entity.Declaration;
import com.mrd.gtimp.business.entity.DeclarationAttachment;
import com.mrd.gtimp.business.entity.DeclarationFree;
import com.mrd.gtimp.business.entity.DeclarationFreeDetail;
import com.mrd.gtimp.business.entity.DeclarationInform;
import com.mrd.gtimp.business.entity.RejectContent;
import com.mrd.gtimp.business.entity.SuiFuDan;
import com.mrd.gtimp.business.repository.CargoDeclaRecordDao;
import com.mrd.gtimp.business.repository.ContacterDao;
import com.mrd.gtimp.business.repository.DeclarationDao;
import com.mrd.gtimp.business.service.cargoDeclaration.component.CargoDeclarationHelper;
import com.mrd.gtimp.order.entity.DeclaContainer;
import com.mrd.gtimp.service.client.CtmsServiceClient;
import com.mrd.gtimp.service.dto.CTMSShipInfoDTO;
import com.mrd.gtimp.v2.datalock.DataLockUtil;
import com.mrd.gtimp.v2.fund.FundIETypeEnum;
import com.mrd.gtimpframe.entity.DeclaRelastionship;
import com.mrd.gtimpframe.entity.RejectCount;
import com.mrd.gtimpframe.repository.UserMapper;
import com.mrd.gtimpframe.service.ChargingService;
import com.mrd.gtimpframe.service.DeclaRelastionshipService;
import com.mrd.gtimpframe.service.RejectCountService;
import com.mrd.spring.repository.BaseRepository;
import com.mrd.util.KeyGenerator;
import com.mrd.util.LoginUtil;
import com.mrd.util.date.DateUtil;

/**
 * <p>
 * application name: gtimp
 * <p>
 * copyright: Copyright@2012 明睿达科技有限公司
 */

/**
 * @author luob
 */
@Service
public class DeclarationBiz extends BaseBiz<Declaration> {

    public static final String ACTIVITI_GRAPH_ID = "orderProcess";

    public static final Logger logger = LoggerFactory.getLogger(DeclarationBiz.class);
    @Resource
    private DeclarationDao declarationDao;
    @Resource
    private DeclarationFreeBiz declarationFreeBiz;
    @Resource
    private DeclarationFreeDetailBiz declarationFreeDetailBiz;
    @Resource
    private ContacterBiz contacterBiz;
    @Resource
    private CommodityBiz commodityBiz;
    @Resource
    private DeclarationInformBiz declarationInformBiz;
    @Resource
    private SuiFuDanBiz suifuBiz;
    @Resource
    private AttachmentBiz attachmentBiz;
    @Resource
    private CompanyQpBiz companyQpBiz;
    @Resource
    private ContractTermsBiz contractTermsBiz;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private ContacterDao contacterDao;
    @Resource
    private PaymentABCBiz paymentABCBiz;
    @Resource
    private FundAccountBiz fundAccountBiz;
    @Resource
    private CargoDeclarationHelper cargoDeclarationHelper;
    @Resource
    private CargoDeclaRecordDao cargoDeclaRecordDao;
    @Resource
    private BusinessKeyBiz businessKeyBiz;
    @Resource
    private BusinessBiz businessBiz;
    @Resource
    private DeclaRelastionshipService declaRelastionshipService;
    @Resource
    private RejectCountService rejectCountService;
    @Resource
    private ChargingService chargingService;
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Resource
    private DataLockUtil dataLockUtil;
    @Resource
    private DeclarationAction dAction;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserDao userDao;

    @Resource
    // 该处指定注入BaseRepository的dao对象
    @Qualifier("declarationDao")
    public void setBaseRepository(BaseRepository<Declaration, String> baseRepository) {
        super.baseRepository = baseRepository;
    }

    /**
     * 复制一份报关单，信息与指定报关单id对应的一致，清除id
     *
     * @param id 指定报关单
     * @return 新的报关单
     */
    public Declaration copyDeclaration(String id) {
        Declaration declaration = baseRepository.findOne(id);
        if (declaration == null) {
            return new Declaration();
        }
        declaration.setId(null);
        declaration.setBusinessId(null);
        if (declaration.getCommodities() != null) {
            declaration.getCommodities().stream().forEach(x -> x.setId(null));
        }
        // if (declaration.getDeclaContainers() != null) {
        declaration.setDeclaContainers(new ArrayList<DeclaContainer>());
        declaration.setContainer_no("");
        declaration.setContainer_no_show("");
        // declaration.getDeclaContainers().stream().forEach(x -> x.setId(null));
        // }
        if (declaration.getSuiFuDans() != null) {
            declaration.getSuiFuDans().stream().forEach(x -> x.setId(null));
        }

        declaration.setTransport_na("");
        declaration.setVoyage_no("");
        declaration.setBl_no("");
        declaration.setExport_port("");
        declaration.setExport_port_code("");
        declaration.setDeclaration_port("");
        declaration.setDeclaration_port_code("");
        declaration.setSupCompany(null);
        return declaration;
    }

    /**
     * 获取业务编号
     *
     * @return 业务编号
     */
    @Transactional
    public synchronized String newBusinessKey() throws Exception {
        String businessIdVal = KeyGenerator.generateNoFromDate("BE", "yyyyMMdd");
        String businessTime = businessIdVal.substring(2);
        String sql = "select max(substr(BUSINESS_ID,11)) from T_BIZ_BASE_BUSINESS where to_char(CTIME,'yyyyMMdd')=:date and business_id like 'BE%'";
        try {
            Map<String, Object> parameters = new HashMap<>();
            parameters.put("date", businessTime);
            List<Object> bus = baseRepository.findEntityBySql(sql, 0, 1, parameters);
            if (CollectionUtils.isEmpty(bus) || bus.get(0) == null) {
                return businessIdVal + "0001";
            }
            String businessNum = (String) bus.get(0);
            businessIdVal = String.format(businessIdVal + "%04d", Integer.parseInt(businessNum) + 1);
            return businessIdVal;
        } catch (QueryException e1) {
            throw new Exception("业务编号获取错误!");
        }
    }

    /**
     * 修改报关单，草稿状态下修改
     *
     * @param declaration 报关单
     */
    // @Transactional
    public Declaration save(Declaration declaration) throws Exception {
        Assert.notNull(declaration, "保存失败，报关单内容为空!");
        try {
            declaration = fillDeclarationMetaData(declaration, Declaration.DeclarationBusinessState.DRAFT_STATE);
        } catch (Exception e) {
            throw new SaveException("保存时发生错误!", e);
        }
        if (!(Declaration.DeclarationBusinessState.DRAFT_STATE.equals(declaration.getState()) || Declaration.DeclarationBusinessState.REJECT_WAIT_REDIT_STATE.equals(declaration.getState()))) {
            throw new SaveException("只能修改草稿状态的报关单!");
        }
        return saveDeclaration(declaration);
    }

    /**
     * 提交报关单
     */
    // @Transactional
    public Declaration submit(Declaration declaration) throws Exception {
        Assert.notNull(declaration, "保存失败，报关单内容为空!");
        // 如果是驳回过的单，建立报关单关系谱
        RejectCount rejectCount = rejectCountService.selectByDid(declaration.getId());
        DeclaRelastionship declaRelastionship = null;
        String did = declaration.getId();
        if (rejectCount != null) {
            declaration = rejectToNew(declaration, rejectCount.getCount() + "");
            if (rejectCount.getCount() == 1) {
                declaRelastionship = new DeclaRelastionship(did);
            } else {
                declaRelastionship = declaRelastionshipService.selectByDeclaId(did);
                declaRelastionship.setParent(did);
            }
        }
        String businessId = declaration.getBusinessId();
        if (StringUtils.isNotEmpty(businessId)) {
            String declarationId = this.findIdByBusinessId(businessId);
            if (StringUtils.isNotEmpty(declarationId)) {
                declaration.setId(declarationId);
            }
        }
        try {
            declaration = fillDeclarationMetaData(declaration, Declaration.DeclarationBusinessState.DRAFT_STATE);// 提交时如果数据未新增则先将状态设置位草稿做后续校验
            declaration.setConfirmTime(new Date());
        } catch (Exception e) {
            throw new SaveException("提交时发生错误!" + e.getMessage(), e);
        }
        if (!Declaration.DeclarationBusinessState.DRAFT_STATE.equals(declaration.getState())) {
            logger.warn("只能提交草稿状态的单证!本单证不为操作状态，直接返回该单证!单证信息为：{}", declaration);
            return declaration;
        }
        declaration.setState(Declaration.DeclarationBusinessState.ORDER_STATE);
        Declaration declarationNew = saveDeclaration(declaration);
        // 如果是驳回过的单，建立报关单关系谱
        if (rejectCount != null) {
            declaRelastionship.setNode(declarationNew.getId());
            declaRelastionshipService.insertSelective(declaRelastionship);
        }
        try {
            runtimeService.startProcessInstanceByKey(ACTIVITI_GRAPH_ID, declaration.getId());
        } catch (Exception e) {
            throw new Exception("流程开启失败，请联系管理员!");
        }
        return declarationNew;
    }

    /**
     * 保存报关单，只有草稿状态或者新建才能创建新的报关单
     */
    // @Transactional
    private Declaration saveDeclaration(Declaration declaration) throws Exception {
        Assert.notNull(declaration, "保存失败，报关单内容为空!");
        try {
            declaration.setMtime(new Date());
            declaration.setModifier(LoginUtil.getLoginAccount());
            if (declaration.getDeclaContainers() == null) {
                declaration.setDeclaContainers(new ArrayList<>());
            } else if (CollectionUtils.isNotEmpty(declaration.getDeclaContainers())) {
                // 去重和设置柜的对应报关单
                List<DeclaContainer> containers = new ArrayList<>();
                Set<String> containerNoSet = new HashSet<>();
                for (DeclaContainer container : declaration.getDeclaContainers()) {
                    String containerNo = container.getContainerNo();
                    // 如果为空或者柜号重复则移除
                    if (StringUtils.isBlank(containerNo) || containerNoSet.contains(containerNo)) {
                        logger.warn("柜号重复!");
                    } else {
                        container.setDeclaration(declaration);
                        containers.add(container);
                        containerNoSet.add(containerNo);
                    }
                }
                declaration.setDeclaContainers(containers);
            }
            if (declaration.getSuiFuDans() == null) {
                declaration.setSuiFuDans(new ArrayList<>());
            } else if (CollectionUtils.isNotEmpty(declaration.getSuiFuDans())) {
                declaration.getSuiFuDans().forEach(x -> x.setDeclaration(declaration));
            }
            if (declaration.getCommodities() == null) {
                declaration.setCommodities(new ArrayList<>());
            } else if (CollectionUtils.isNotEmpty(declaration.getCommodities())) {
                declaration.getCommodities().forEach(x -> x.setDeclaration(declaration));
            }

            Declaration d = baseRepository.save(declaration);
            if (StringUtils.isNoneEmpty(declaration.getTempAttachmentBillNo())) {
                Filter filters = new Filter();
                filters.addRule(new SearchRule("bill_no", SearchRuleOption.eq, declaration.getTempAttachmentBillNo()));
                List<DeclarationAttachment> attachments = declarationAttachmentBiz.findEntityByFilter(0, 10, filters, null);
                for (DeclarationAttachment attachment1 : attachments) {
                    if (attachment1.getDeclaration() == null) {
                        attachment1.setDeclaration(declaration);
                        attachment1.setBill_no(declaration.getId());
                        declarationAttachmentBiz.saveOrupdateEntity(attachment1);
                    }
                }
            }
            if (StringUtils.isNotEmpty(d.getId())) {
                declaration.setId(d.getId());
                ContractTerms contractTerms = contractTermsBiz.findEntityByDeclaration(d);
                if (contractTerms == null) {
                    contractTerms = new ContractTerms();
                    contractTerms.setDeclaration(d);
                    contractTerms.setContract_total_chn(d.getTotal_money());
                    contractTerms.setContract_total_en(d.getTotal_money());
                    List<Commodity> commodities = d.getCommodities();
                    if (commodities != null && commodities.size() > 0) {
                        contractTerms.setCurrency_chn(commodities.get(0).getCurrency());
                        contractTerms.setCurrency_en(commodities.get(0).getCurrency());
                        contractTerms.setDestination_port_chn(commodities.get(0).getDestination());
                    }
                    contractTerms.setPrice_terms_chn(d.getDeal_mode());
                    contractTerms.setPrice_terms_en(d.getDeal_mode());
                    contractTerms.setPacking_chn(d.getGoods_package());
                    contractTerms.setLoading_port_chn(d.getGoods_addr());
                    contractTerms.setShipping_marks_chn(d.getCarton());
                    contractTermsBiz.saveOrupdateEntity(contractTerms);
                    d.setContract_terms_type("1");
                    d.setContractTerms(contractTerms);
                    baseRepository.save(d);
                }
            }

        } catch (Exception exception) {
            logger.error("保存时发生异常", exception);
            throw new SaveException("保存时发生异常!", exception);
        }
        return declaration;
    }

    @Resource
    DeclarationAttachmentBiz declarationAttachmentBiz;
    @Resource
    CompanyBiz companyBiz;

    /**
     * 对报关单填充由后台控制的信息，如业务编号，下单公司....
     *
     * @param declaration  待填充的报关单
     * @param defaultState 如果是新增情况填充的状态
     * @return 填充了信息后的报关单
     */
    private Declaration fillDeclarationMetaData(Declaration declaration, String defaultState) throws Exception {
        if (StringUtils.isEmpty(declaration.getId())) {
            try {
                // String businessId = newBusinessKey();
                String businessId = businessKeyBiz.newBusinessKey();
                declaration.setBusinessId(businessId); // 业务编号
                declaration.setCustomer(LoginUtil.getLoginUser().getCompany()); // 下单的客户公司/代理公司
                declaration.setCreator(LoginUtil.getLoginUser().getAccount());
                // declaration.setCTIME(new Date());
                declaration.setMaking_date(new Date());
                declaration.setUnityNo(UUID.randomUUID().toString()); // 自动生成统一编号
                declaration.setPayment_type("0");// 设置支付状态
                declaration.setCtime(new Date());
                declaration.setCreator(LoginUtil.getLoginAccount());
                declaration.setState(defaultState);
            } catch (Exception e) {
                throw new Exception("业务编号生成出错，请稍后再试!", e);
            }
        } else {
            Declaration declarationOld = baseRepository.findOne(declaration.getId());
            checkDeclareCanUpdate(declarationOld);
            declaration.setBusinessId(declarationOld.getBusinessId()); // 业务编号
            declaration.setCustomer(declarationOld.getCustomer()); // 下单的客户公司/代理公司
            declaration.setCreator(declarationOld.getCreator());
            declaration.setCtime(declarationOld.getCtime());
            declaration.setMaking_date(declarationOld.getMaking_date());
            declaration.setUnityNo(declarationOld.getUnityNo()); // 自动生成统一编号
            declaration.setPayment_type(declarationOld.getPayment_type());// 设置支付状态
            declaration.setState(declarationOld.getState());
        }
        declaration.setShipper(contacterDao.findOne(LoginUtil.getLoginUser().getId()));
        Company shenbaoCompany = companyBiz.findEntityById(declaration.getSupCompany().getId());
        declaration.setShenbao_company_co(shenbaoCompany.getCom_customs_code());
        declaration.setShenbao_company_name(shenbaoCompany.getName());
        return declaration;
    }

    /**
     * 将需要支付的费用填充到报关单对象中
     *
     * @param id 报关单id
     * @return 填充了费用的报关单
     */
    @Transactional
    public Declaration fillPayFeeToDeclaration(String id) throws Exception {
        Declaration dc = getCanPayDeclaration(id);
        List<Declaration> declarationList = new ArrayList<>();
        declarationList.add(dc);
        try {
            List<DeclarationFreeDetail> declarationFreeDetails = declarationFreeDetailBiz.findAllEntity();
            declarationList = declarationFreeBiz.countFree(declarationList, declarationFreeDetails);
            dc = declarationList.get(0);

            DeclarationFreeDetail freeDetail = dc.getDeclarationFreeDetail();
            // 结算需要报检的报关单
            // dc.setDeclaration_free(dc.getDeclaration_free() + (new
            // Double(freeDetail.getInner_inspection()) - new
            // Double(freeDetail.getOutter_inspection())));
            // 结算需要熏蒸的报关单
            // dc.setDeclaration_free(dc.getDeclaration_free() + (new
            // Double(freeDetail.getSteaming_base()) + new Integer(dc.getContainer_num()) * new
            // Double(freeDetail.getSteaming_container())));
            // 结算需要报市场家私的报关单
            // dc.setDeclaration_free(dc.getDeclaration_free() + (new
            // Double(freeDetail.getMmf_free()) * Integer.parseInt(dc.getContainer_num())));
            DeclarationFree free = declarationFreeBiz.saveFeeForDeclaration(dc);
            dc.setDeclarationFree(free);
        } catch (FeeException e) {
            throw e;
        } catch (Exception e) {
            throw new Exception("费用计算失败，请稍后再试");
        }
        return dc;
    }

    /**
     * 取得可以进行支付的报关单
     *
     * @param id id
     * @return 可以支付的报关单
     */
    public Declaration getCanPayDeclaration(String id) {
        Assert.notNull(id, "报关单id为空!");
        // todo 暂时就查两次，等需要进行速率优化时再处理
        Declaration declaration = declarationDao.findByIdAndState(id, Declaration.DeclarationBusinessState.ORDER_STATE);
        if (declaration == null) {
            declaration = declarationDao.findByIdAndState(id, Declaration.DeclarationBusinessState.REJECT_WAIT_REDIT_STATE);
        }
        if (declaration != null && !declaration.getPayment_type().equals("0")) {
            declaration = null;
        }
        if (declaration != null && !declaration.getPayment_type().equals("0")) {
            declaration = null;
        }
        Assert.notNull(declaration, "无法查询到指定订单，请确认该订单是否存在或已完成支付!");
        return declaration;
    }

    /**
     * 判断报关状态是否可修改
     *
     * @param declaration 需要被验证的报关单
     * @throws SaveException 如果不允许修改则抛出该异常
     */
    @Transactional
    public void checkDeclareCanUpdate(Declaration declaration) throws SaveException {
        // 非草稿状态不允许修改
        if (!(Declaration.DeclarationBusinessState.DRAFT_STATE.equals(declaration.getState()) || Declaration.DeclarationBusinessState.REJECT_WAIT_REDIT_STATE.equals(declaration.getState()) || Declaration.DeclarationBusinessState.REJECT_STATE.equals(declaration.getState()))) {
            throw new SaveException("该单证已提交不允许操作!");
        }
    }

    /**
     * 检查报关单是否可支付
     *
     * @param declaration 报关单
     */
    @Transactional
    public void checkDeclareCanPay(Declaration declaration) throws Exception {
        // 非草稿状态不允许修改
        if (!(Declaration.DeclarationBusinessState.DRAFT_STATE.equals(declaration.getState()) || Declaration.DeclarationBusinessState.REJECT_STATE.equals(declaration.getState()))) {
            throw new Exception("只能支付已提交状态的报关单!");
        }
    }

    /**
     * 更新报关单支付状态
     *
     * @param id 报关单id
     */
    @Transactional
    public void updatePayState(String id) throws SaveException {
        Declaration declaration = declarationDao.findOne(id);
        updatePayState(declaration);
    }

    /**
     * 更新报关单为已支付
     *
     * @param declaration 报关单
     */
    @Transactional
    public void updatePayState(Declaration declaration) throws SaveException {
        declaration.setPayment_type("1");
        declaration.setPaymentTime(new Date());
        this.changeState(declaration);
        /*
         * Task task = taskService.createTaskQuery().processInstanceBusinessKey(declaration.getId())
         * .singleResult(); declaration.setPayment_type("1"); Map<String, Object> parameters = new
         * HashMap<>(); parameters.put("declaration", declaration); taskService.complete(task.getId(),
         * parameters);
         */
    }

    public void submitAndPay(Declaration declaration) throws SaveException {
        Assert.isNull(declaration, "提交失败，报关单内容为空!");
        if (StringUtils.isNoneEmpty(declaration.getId())) {
            Declaration declarationOld = baseRepository.findOne(declaration.getId());
            // 非草稿和驳回状态不允许提交
            if (!Declaration.DeclarationBusinessState.DRAFT_STATE.equals(declarationOld.getState()) || !Declaration.DeclarationBusinessState.REJECT_STATE.equals(declarationOld.getState())) {
                throw new SaveException("只能修改草稿和驳回状态的报关单!");
            }
        }
        declaration.setState(Declaration.DeclarationBusinessState.ORDER_STATE);
        if (CollectionUtils.isNotEmpty(declaration.getDeclaContainers())) {
            declaration.getDeclaContainers().forEach(x -> x.setDeclaration(declaration));
        }
        if (CollectionUtils.isNotEmpty(declaration.getSuiFuDans())) {
            declaration.getSuiFuDans().forEach(x -> x.setDeclaration(declaration));
        }
        if (CollectionUtils.isNotEmpty(declaration.getCommodities())) {
            declaration.getCommodities().forEach(x -> x.setDeclaration(declaration));
        }
        if (CollectionUtils.isNotEmpty(declaration.getSuiFuDans())) {
            declaration.getSuiFuDans().forEach(x -> x.setDeclaration(declaration));
        }
        runtimeService.startProcessInstanceByKey(ACTIVITI_GRAPH_ID, declaration.getId());
    }

    public void updateValidatePass(String id) throws Exception {
        try {
            User user = (User) HttpUtils.getRequest().getSession().getAttribute(SystemConstants.CURRENT_USER);
            String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
            String sql = "update T_BIZ_BASE_BUSINESS set VALIDATOR_ID='" + LoginUtil.getLoginUser().getId() + "',  VALIDATE_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
            baseRepository.updateBySql(sql);
            System.out.println("通过审核执行更新表T_BIZ_BASE_BUSINESS=======" + sql);

            sql = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_02 + "' where ID='" + id + "'";
            baseRepository.updateBySql(sql);
            System.out.println("通过审核执行更新表T_BIZ_DECLARATION=======" + sql);
            System.out.println("通过审核更新成功id=========" + id);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void updateValidateUpload(String id) throws Exception {
        System.out.println(this.getClass().getName() + "-->updateValidateUpload方法开发中");
    }

    @Transactional
    public void updateValidateUpload(String id, String validator) throws Exception {
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sql = "update T_BIZ_BASE_BUSINESS set UPLOADER_EXT='" + validator + "',  UPLOAD_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
        jdbcTemplate.update(sql);

        String sql2 = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_04 + "' where ID='" + id + "'";
        jdbcTemplate.update(sql2);
    }

    public void updateValidateReject(String id) throws Exception {
        User user = (User) HttpUtils.getRequest().getSession().getAttribute(SystemConstants.CURRENT_USER);
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sql = "update T_BIZ_BASE_BUSINESS set VALIDATOR_ID='" + user.getId() + "',  VALIDATE_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
        baseRepository.updateBySql(sql);

        sql = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_03 + "' where ID='" + id + "'";
        baseRepository.updateBySql(sql);
    }

    public void updateBizConfirm(String id) throws Exception {
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sql = "update T_BIZ_BASE_BUSINESS set CONFIRM_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
        baseRepository.updateBySql(sql);
        System.out.println("提交订单执行表T_BIZ_BASE_BUSINESS======" + sql);

        sql = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_01 + "' where ID='" + id + "'";
        baseRepository.updateBySql(sql);
        System.out.println("提交订单执行表T_BIZ_DECLARATION======" + sql);
    }

    /**
     * 非佛港海关放行
     */
    public void updateCustomsPassDeclaration(String id) throws QueryException, SaveException {
        User user = (User) HttpUtils.getRequest().getSession().getAttribute(SystemConstants.CURRENT_USER);
        String strs[] = id.split(",");
        for (int i = 0; i < strs.length; i++) {
            Declaration declaration = this.findEntityById(strs[i]);
            declaration.setState(BaseTypeConstant.DECLARATIONSTATE_10);
            declaration.setValidateTime(new Date());
            declaration.setValidator(user);
            declaration.setCustom_status(BaseTypeConstant.CUSTOMSDECLARATIONSTATE_1);
            declaration.setCustom_time(new Date());
            this.changeState(declaration);
        }
    }

    /**
     * 非佛港商检放行
     */
    public void updateCommodityInspectionPass(String id) throws QueryException, SaveException {
        User user = (User) HttpUtils.getRequest().getSession().getAttribute(SystemConstants.CURRENT_USER);
        String strs[] = id.split(",");
        for (int i = 0; i < strs.length; i++) {
            Declaration declaration = this.findEntityById(strs[i]);
            declaration.setValidator(user);
            declaration.setValidateTime(new Date());
            declaration.setState(BaseTypeConstant.DECLARATIONSTATE_11);
            declaration.setCheck_status(BaseTypeConstant.COMMODITYINSPECTIONDECLARATIONSTATE_1);
            declaration.setCheck_time(new Date());
            this.changeState(declaration);
        }
    }

    /**
     * 非佛港完成报关
     */

    public void updateFinishDeclarationPass(String id) throws Exception {
        User user = (User) HttpUtils.getRequest().getSession().getAttribute(SystemConstants.CURRENT_USER);
        String strs[] = id.split(",");
        String ids = "";
        for (int i = 0; i < strs.length; i++) {
            ids += "'" + strs[i] + "',";
        }
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sql = "update T_BIZ_BASE_BUSINESS set VALIDATOR_ID='" + user.getId() + "',  VALIDATE_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID in (" + ids.subSequence(0, ids.length() - 1) + ")";
        System.out.println("sql1====" + sql);
        baseRepository.updateBySql(sql);
        sql = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_05 + "' where ID in (" + ids.subSequence(0, ids.length() - 1) + ")";
        System.out.println("sql2====" + sql);
        baseRepository.updateBySql(sql);
    }

    /*
     * (non-Javadoc)
     *
     * @see com.mrd.gtimp.business.biz.BaseBusinessBiz#saveBusiness(com.mrd.gtimp.business.pojo.
     * BaseBusiness )
     */

    public void saveBusiness(Declaration declaration, List<String> properties) throws Exception {
        if (null != declaration && null != declaration.getSupCompany() && StringUtils.isNotEmpty(declaration.getSupCompany().getId())) {
            contacterBiz.saveConcater(declaration.getShipper(), declaration.getCustomer(), declaration.getCreator());
            if (StringUtils.isEmpty(declaration.getId())) {
                declaration.setId(null);
                saveOrupdateEntity(declaration);
            } else {
                updateEntity(declaration, properties);
            }
            List<Commodity> commodities = declaration.getCommodities();
            String hql = "from com.mrd.gtimp.business.entity.Commodity c where c.declaration='" + declaration.getId() + "'";
            List<Commodity> oCommodities = commodityBiz.findEntityByHql(hql, 0, 1, null);
            if (oCommodities != null) {
                for (Commodity commodity : oCommodities) {
                    commodityBiz.delete(commodity);
                }
            }
            if (null != declaration.getCommodities()) {
                for (Commodity commodity : commodities) {
                    // if(StringUtils.isEmpty(commodity.getId())) {
                    commodity.setId(null);
                    // }
                    if (null == commodity.getDeclaration()) {
                        commodity.setDeclaration(declaration);
                    }
                    commodityBiz.saveOrupdateEntity(commodity);
                }
            }
            if (declaration.getCompany_co() != null && StringUtils.isNotEmpty(declaration.getCompany_co())) {
                String sql = "update CDAMS_QP_COMPANYS set COMPANY_ADDRESS = '" + declaration.getSeller_address() + "', COMPANY_PHONE = '" + declaration.getSeller_phone() + "', COMPANY_FAX = '" + declaration.getSeller_fax() + "' where COMPANY_CODE = '" + declaration.getCompany_co() + "'";
                baseRepository.updateBySql(sql);
            }

            if (declaration.getContractTerms() != null) {
                if (declaration.getContractTerms().getDeclaration() == null) {
                    declaration.getContractTerms().setDeclaration(declaration);
                }
                if (StringUtils.isEmpty(declaration.getContractTerms().getId())) {
                    declaration.getContractTerms().setId(null);
                    contractTermsBiz.saveOrupdateEntity(declaration.getContractTerms());
                } else {
                    if (declaration.getContractTerms() != null) {
                        ContractTerms contractTerms = new ContractTerms();
                        List<String> propertiesCt = new ArrayList<String>();
                        propertiesCt.add("contract_total_chn");
                        propertiesCt.add("contract_total_en");
                        propertiesCt.add("price_terms_chn");
                        propertiesCt.add("price_terms_en");
                        propertiesCt.add("packing_chn");
                        propertiesCt.add("packing_en");
                        propertiesCt.add("shipment_time_chn");
                        propertiesCt.add("shipment_time_en");
                        propertiesCt.add("loading_port_chn");
                        propertiesCt.add("loading_port_en");
                        propertiesCt.add("destination_port_chn");
                        propertiesCt.add("destination_port_en");
                        propertiesCt.add("payment_terms_chn");
                        propertiesCt.add("payment_terms_en");
                        propertiesCt.add("shipping_marks_chn");
                        propertiesCt.add("shipping_marks_en");
                        propertiesCt.add("currency_chn");
                        propertiesCt.add("currency_en");

                        contractTerms.setId(declaration.getContractTerms().getId());
                        contractTerms.setContract_total_chn(declaration.getContractTerms().getContract_total_chn());
                        contractTerms.setContract_total_en(declaration.getContractTerms().getContract_total_en());
                        contractTerms.setPrice_terms_chn(declaration.getContractTerms().getPrice_terms_chn());
                        contractTerms.setPrice_terms_en(declaration.getContractTerms().getPrice_terms_en());
                        contractTerms.setPacking_chn(declaration.getContractTerms().getPacking_chn());
                        contractTerms.setPacking_en(declaration.getContractTerms().getPacking_en());
                        contractTerms.setShipment_time_chn(declaration.getContractTerms().getShipment_time_chn());
                        contractTerms.setShipment_time_en(declaration.getContractTerms().getShipment_time_en());
                        contractTerms.setLoading_port_chn(declaration.getContractTerms().getLoading_port_chn());
                        contractTerms.setLoading_port_en(declaration.getContractTerms().getLoading_port_en());
                        contractTerms.setDestination_port_chn(declaration.getContractTerms().getDestination_port_chn());
                        contractTerms.setDestination_port_en(declaration.getContractTerms().getDestination_port_en());
                        contractTerms.setPayment_terms_chn(declaration.getContractTerms().getPayment_terms_chn());
                        contractTerms.setPayment_terms_en(declaration.getContractTerms().getPayment_terms_en());
                        contractTerms.setShipping_marks_chn(declaration.getContractTerms().getShipping_marks_chn());
                        contractTerms.setShipping_marks_en(declaration.getContractTerms().getShipping_marks_en());
                        contractTerms.setCurrency_chn(declaration.getContractTerms().getCurrency_chn());
                        contractTerms.setCurrency_chn(declaration.getContractTerms().getCurrency_en());
                        contractTermsBiz.updateEntity(contractTerms, propertiesCt);
                    }
                }
            } else {
                String sql = "select t.* from t_biz_contract_terms t where t.declaration_id = '" + declaration.getId() + "'";
                int countNum = contractTermsBiz.findEntityCountBySql(sql, null);
                if (countNum == 0) {
                    // if("".equals(declaration.getContract_terms_type())) {
                    ContractTerms contractTerms = new ContractTerms();
                    contractTerms.setId(null);
                    contractTerms.setContract_total_chn(declaration.getTotal_money());
                    contractTerms.setContract_total_en(declaration.getTotal_money());
                    contractTerms.setPrice_terms_chn(declaration.getDeal_mode());
                    contractTerms.setPrice_terms_en(declaration.getDeal_mode());
                    contractTerms.setPacking_chn(declaration.getGoods_package());
                    contractTerms.setLoading_port_chn(declaration.getExport_port());
                    contractTerms.setDestination_port_chn(declaration.getCommodities().get(0).getDestination());
                    contractTerms.setPayment_terms_chn(declaration.getLc_type());
                    contractTerms.setShipping_marks_chn(declaration.getCarton());
                    contractTerms.setCurrency_chn(declaration.getCommodities().get(0).getCurrency());
                    contractTerms.setDeclaration(declaration);
                    contractTermsBiz.saveOrupdateEntity(contractTerms);
                    declaration.setContract_terms_type("1");
                    updateEntity(declaration, properties);
                    // }
                }
            }

            if (null != declaration.getSuiFuDans()) {
                for (SuiFuDan sfd : declaration.getSuiFuDans()) {
                    if (StringUtils.isEmpty(sfd.getId())) {
                        sfd.setId(null);
                    }
                    if (null == sfd.getDeclaration()) {
                        sfd.setDeclaration(declaration);
                    }
                    suifuBiz.saveOrupdateEntity(sfd);
                }
            }
            if (declaration.getDeclarationInform() != null) {
                if (StringUtils.isEmpty(declaration.getDeclarationInform().getId())) {
                    declaration.getDeclarationInform().setId(null);
                }
                if (null == declaration.getDeclarationInform().getDeclaration()) {
                    declaration.getDeclarationInform().setDeclaration(declaration);
                }
                declarationInformBiz.saveOrupdateEntity(declaration.getDeclarationInform());
            }
        }
    }

    public void updateValidatePass(String id, String validator) throws Exception {
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sql = "update T_BIZ_BASE_BUSINESS set VALIDATOR_EXT='" + validator + "',  VALIDATE_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
        baseRepository.updateBySql(sql);

        sql = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_02 + "' where ID='" + id + "'";
        baseRepository.updateBySql(sql);
    }

    public void updateValidateReject(String id, String validator) throws Exception {
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sql = "update T_BIZ_BASE_BUSINESS set VALIDATOR_EXT='" + validator + "',  VALIDATE_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
        baseRepository.updateBySql(sql);

        sql = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_03 + "' where ID='" + id + "'";
        baseRepository.updateBySql(sql);
    }

    public void updateValidateFinish(String id, String validator) throws Exception {
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sql = "update T_BIZ_BASE_BUSINESS set FINISHER_EXT='" + validator + "',  FINISH_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
        baseRepository.updateBySql(sql);

        sql = "update T_BIZ_DECLARATION set STATE = '" + BaseTypeConstant.DECLARATIONSTATE_05 + "' where ID='" + id + "'";
        System.out.println("更新货运平台报关状态结束语句===========" + sql);
        baseRepository.updateBySql(sql);
    }

    /**
     * 报关系统反馈状态(初审、复审、现场递单等)
     */

    public void updateValidateDeclarationTrackState(String id, String validator, String state) throws Exception {
        String validateDateStr = DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        String declarationState = "";
        String sql = "update T_BIZ_BASE_BUSINESS set FINISHER_EXT='" + validator + "',  FINISH_TIME=to_date('" + validateDateStr + "','yyyy-mm-dd HH24:MI:SS') where ID='" + id + "'";
        baseRepository.updateBySql(sql);

        if ("a".equals(state)) {
            declarationState = BaseTypeConstant.DECLARATIONSTATE_06;
        } else if ("c".equals(state)) {
            declarationState = BaseTypeConstant.DECLARATIONSTATE_07;
        } else if ("d".equals(state)) {
            declarationState = BaseTypeConstant.DECLARATIONSTATE_08;
        } else if ("e".equals(state)) {
            declarationState = BaseTypeConstant.DECLARATIONSTATE_09;
        } else if ("f".equals(state)) {
            declarationState = BaseTypeConstant.DECLARATIONSTATE_10;
        }

        sql = "update T_BIZ_DECLARATION set STATE = '" + declarationState + "' where ID='" + id + "'";
        baseRepository.updateBySql(sql);
    }

    /**
     * 更新declaration的支付状态
     */

    public void updatePaymentType(String id, String payMent_type) throws Exception {
        String sql = "update T_BIZ_DECLARATION set PAYMENT_TYPE ='" + payMent_type + "'," +
                "PAYMENT_TIME=TO_DATE(TO_CHAR(sysdate, 'yyyy/mm/dd hh24:mi:ss'), 'yyyy/mm/dd hh24:mi:ss')  where ID='" + id + "'";
        baseRepository.updateBySql(sql);
    }

    public void updateBizAddInform(String id) throws Exception {
        // user = customer
        User user = (User) HttpUtils.getRequest().getSession().getAttribute(SystemConstants.CURRENT_USER);
        Declaration entity = findEntityById(id);
        DeclarationInform tentity = new DeclarationInform();
        tentity.setId(null);
        tentity.setDeclaration(entity);
        tentity.setConfirmState("0");
        tentity.setCreateTime(new Date());
        tentity.setCreator(user);
        tentity.setCustomerCompany(entity.getCustomer());
        tentity.setSupCompany(entity.getSupCompany());

        declarationInformBiz.saveOrupdateEntity(tentity);
        //
    }

    public DeclarationInformBiz getDeclarationInformBiz() {
        return declarationInformBiz;
    }

    public void setDeclarationInformBiz(DeclarationInformBiz declarationInformBiz) {
        this.declarationInformBiz = declarationInformBiz;
    }

    public void updateValidateCancel(String id) throws Exception {
    }

    public void updateValidateApplyCancel(String id) throws Exception {
    }

    // ==============================gtimp 3.0=========================================

    @Resource
    private EvaluationBiz evaluationBiz;

    @Resource
    private RejectContentBiz rejectContentBiz;

    public Page<Declaration> findByJqgrid(Jqgrid jqgrid) throws QueryException {
        return findByJqgrid(jqgrid, null);
    }

    public Page<Declaration> findByJqgrid(Jqgrid jqgrid, String graphName) throws QueryException {
        Page<Declaration> declarationPage;
        if (StringUtils.isNotEmpty(graphName)) {
            declarationPage = super.findByJqgrid(jqgrid, graphName);
        } else {
            declarationPage = super.findByJqgrid(jqgrid);
        }
        List<String> ids = declarationPage.getContent().stream().map(BaseBusiness::getId).collect(Collectors.toList());
        Map<String, Evaluation> map = evaluationBiz.findEvaluationMapWithBusinessIds(ids);
        for (Declaration declaration : declarationPage.getContent()) {
            declaration.setEvaluation(map.get(declaration.getId()));
        }
        return declarationPage;
    }

    /**
     * 报关单受理
     */
    @Transactional
    public void doValidAndLogOpa(Declaration declaration) throws SaveException {
        declaration.setState(Declaration.DeclarationBusinessState.PASS_STATE);
        declaration.setValidateTime(new Date());
        declaration.setValidator(LoginUtil.getLoginUser());
        this.changeState(declaration);
    }

    /**
     * 通过一体化-报关单受理
     *
     * @author han
     */
    @Transactional
    public void doSecondSupValidAndLogOpa(Declaration declaration) throws Exception {
        declaration.setState(Declaration.DeclarationBusinessState.PASS_STATE);
        declaration.setValidateTime(new Date());
        declaration.setValidator(LoginUtil.getLoginUser());
        updateSecondSup(declaration);
        this.changeState(declaration);
    }

    /**
     * 通过一体化-补料
     *
     * @author han
     */
    @Transactional
    public void doOfflineBLAndLogOpa(Declaration declaration) throws Exception {
        declaration.setState(Declaration.DeclarationBusinessState.SEC_PAS);
        declaration.setValidateTime(new Date());
        declaration.setValidator(LoginUtil.getLoginUser());
        updateSecondSup(declaration);
        this.changeState(declaration);
    }

    /**
     * 报关单驳回
     */
    @Transactional
    public void doRejectAndLogOpa(Declaration declaration, String content) throws Exception {
        RejectContent rejectContent = new RejectContent();
        rejectContent.setContent(content);
        rejectContent.setDeclaration(declaration);
        rejectContent.setRejectDate(new Date());
        rejectContent.setRejectPerson(LoginUtil.getLoginUser().getName());
        rejectContentBiz.saveOrupdateEntity(rejectContent);
        List<RejectContent> rejectContents = new ArrayList<>();
        rejectContents.add(rejectContent);
        declaration.setRejectContents(rejectContents);
        declaration.setState(Declaration.DeclarationBusinessState.REJECT_STATE);

        // ^^^^^^^^^以上报关单留底^^^^^^^^
        // vvvvvvvvv以下报关单放在客户驳回列表中待修改vvvvvvv
        copyDeclarationAndSaveForCustomRejectEdit(declaration);
        // 驳回流程
        this.changeState(declaration);


        List<Object> fee = fundFlowBiz.findObjectBySql("select p.free from t_biz_fund_flow f left join t_biz_declara_free p on f.bill_no=p.pay_id where F.FINANCIAL_TYPE='OUT' and p.declaration_id=:did", 0, 1, new HashMap<String, Object>() {
            {
                put("did", declaration.getId());
            }
        });

        if (fee == null || fee.isEmpty()) {
            throw new Exception("驳回出错！");
        }
        fundFlowBiz.addFlow(declaration.getCustomer(), ((BigDecimal) fee.get(0)).doubleValue(), FundIETypeEnum.C_REJECT_FEE, declaration.getBusinessId());
        fundFlowBiz.addFlow(declaration.getSupCompany(), ((BigDecimal) fee.get(0)).doubleValue(), FundIETypeEnum.S_REJECT_FEE, declaration.getBusinessId());

    }

    @Resource
    private FundFlowBiz fundFlowBiz;

    /**
     * 复制并保存对应客户驳回待修改状态的报关单
     *
     * @param declaration 原报关单
     */
    @Transactional
    public Declaration copyDeclarationAndSaveForCustomRejectEdit(Declaration declaration) {
        Declaration newDeclaration = new Declaration();
        try {
            // 开始复制主要属性
            BeanUtils.copyProperties(newDeclaration, declaration);
            List<Commodity> commos = declaration.getCommodities();
            List<DeclaContainer> containers = declaration.getDeclaContainers();
            List<SuiFuDan> sfds = declaration.getSuiFuDans();
            List<Commodity> commoCopys = new ArrayList<>();
            List<DeclaContainer> containerCopys = new ArrayList<>();
            List<SuiFuDan> sfdCopys = new ArrayList<>();

            if (CollectionUtils.isNotEmpty(commos)) {
                for (Commodity commo : commos) {
                    Commodity commodity = new Commodity();
                    BeanUtils.copyProperties(commodity, commo);
                    commodity.setId(null);
                    commoCopys.add(commodity);
                }
            }
            if (CollectionUtils.isNotEmpty(sfds)) {
                for (SuiFuDan sfd : sfds) {
                    SuiFuDan suiFuDan = new SuiFuDan();
                    BeanUtils.copyProperties(suiFuDan, sfd);
                    suiFuDan.setId(null);
                    sfdCopys.add(suiFuDan);
                }
            }
            if (CollectionUtils.isNotEmpty(containers)) {
                for (DeclaContainer container : containers) {
                    DeclaContainer declaContainer = new DeclaContainer();
                    BeanUtils.copyProperties(declaContainer, container);
                    declaContainer.setId(null);
                    containerCopys.add(declaContainer);
                }
            }
            newDeclaration.setCommodities(commoCopys);
            newDeclaration.setDeclaContainers(containerCopys);
            newDeclaration.setSuiFuDans(sfdCopys);
            newDeclaration.setRejectContents(null);
            newDeclaration.setRejectContents(null);
            newDeclaration.setBusinessId(newDeclaration.getBusinessId() + "_b");
            newDeclaration.setBusinessId(declaration.getBusinessId());
            newDeclaration.setDiDans(null);
            newDeclaration.setInspectionGoodsList(null);
            newDeclaration.setDeclareState(null);
            newDeclaration.setUnityNo(null);
            newDeclaration.setId(null);
            // fillDeclarationMetaData(newDeclaration,
            // Declaration.DeclarationBusinessState.REJECT_WAIT_REDIT_STATE);
            newDeclaration.setState(Declaration.DeclarationBusinessState.REJECT_WAIT_REDIT_STATE);
            Assert.notNull(newDeclaration, "报关单驳回时出错了！！");
            newDeclaration = saveDeclaration(newDeclaration);
            if (declaration.getRejectContents() != null && declaration.getRejectContents().size() > 0) {
                for (RejectContent rejectContent : declaration.getRejectContents()) {
                    RejectContent contentCopy = new RejectContent();
                    BeanUtils.copyProperties(contentCopy, rejectContent);
                    contentCopy.setId(null);
                    contentCopy.setDeclaration(newDeclaration);
                    rejectContentBiz.saveOrupdateEntity(contentCopy);
                }

            }
            List<DeclarationAttachment> declarationAttachments = declarationAttachmentBiz.findByDeclaration(declaration);
            if (CollectionUtils.isNotEmpty(declarationAttachments)) {
                for (DeclarationAttachment declarationAttachment : declarationAttachments) {
                    DeclarationAttachment attachmentCopy = new DeclarationAttachment();
                    BeanUtils.copyProperties(attachmentCopy, declarationAttachment);
                    attachmentCopy.setId(null);
                    attachmentCopy.setBill_no(newDeclaration.getId());
                    attachmentCopy.setDeclaration(newDeclaration);
                    declarationAttachmentBiz.saveOrupdateEntity(attachmentCopy);
                }
            }

        } catch (Exception e) {
            Assert.notNull(null, "报关单驳回时出错了！！");
        }
        return newDeclaration;
    }

    /**
     * 改变报关单状态
     *
     * @param declaration 需要从数据库读取出来，不然更新数据的时候会清空数据
     */
    @Transactional
    public void changeState(Declaration declaration) throws SaveException {
        List<Task> tasks = taskService.createTaskQuery().processInstanceBusinessKey(declaration.getId()).orderByTaskId().desc().listPage(0, 1);
        if (CollectionUtils.isEmpty(tasks)) {
            // 执行数据库更新
            // List<String> prop = new ArrayList<>();
            // prop.add("state");
            // this.updateEntity(declaration, prop);
            declarationDao.save(declaration);
        } else {
            // 执行流程更新
            Task task = tasks.get(0);
            Map<String, Object> parameters = new HashMap<>();
            parameters.put("declaration", declaration);
            taskService.complete(task.getId(), parameters);
        }
    }

    /**
     * @param declarationId 报关单ID
     * @return 对应报关单ID的报关单状态和支付状态
     */
    public String[] getDeclarationStateAndPaymentType(String declarationId) {
        Assert.notNull(declarationId, "报关单ID为空");
        List<Object[]> list = declarationDao.findByStateAndPaymentType(declarationId);
        Assert.notEmpty(list, "没有找到指定的报关单");
        Object[] stateAndPaymentType = list.get(0);
        return new String[]{stateAndPaymentType[0].toString(), stateAndPaymentType[1].toString()};
    }

    /**
     * 将报关单中的2.0柜数据装成3.0柜数据
     *
     * @param declaration 报关单
     */
    public void containerNoShowConvertToDeclaContainers(Declaration declaration) {
        String containerNoShow = declaration.getContainer_no_show();
        if (StringUtils.isNotEmpty(containerNoShow)) {
            List<DeclaContainer> containers = new ArrayList<>();
            JSONArray jsonArray = JSON.parseArray(containerNoShow);
            Map<String, String> filterMap = new HashMap<>();

            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject containerObject = jsonArray.getJSONObject(i);
                String ctSize = containerObject.getString("CT_SIZE");
                String containerNo = containerObject.getString("CONTAINER_NO");
                if (filterMap.get(containerNo) == null) {
                    DeclaContainer container = new DeclaContainer();
                    container.setDeclaration(declaration);
                    container.setContainerStandard(ctSize);
                    container.setContainerNo(containerNo);
                    containers.add(container);
                    filterMap.put(containerNo, containerNo);
                }
            }
            declaration.setDeclaContainers(containers);
        }
    }

    /**
     * 通过业务编码查询ID
     *
     * @param businessId 业务编码
     */
    public String findIdByBusinessId(String businessId) {
        if (StringUtils.isNotEmpty(businessId)) {
            Object result = declarationDao.findIdByBusinessId(businessId);
            return result == null ? null : result.toString();
        } else {
            return null;
        }
    }

    /**
     * 通过业务编号查询报关单
     */
    public Declaration findEntityByBusinessId(String businessId) {
        if (StringUtils.isNotEmpty(businessId)) {
            return declarationDao.findEntityByBusinessId(businessId);
        } else {
            return null;
        }
    }


    /**
     * 根据柜号查出所有报关单
     */
    public List<Declaration> findListByContainerNo(String containerNo) {
        if (StringUtils.isNotEmpty(containerNo)) {
            return declarationDao.findByContainerNo(containerNo);
        }
        return null;
    }

    /**
     * 支付报关单，可以进行多单支付
     *
     * @param pay_id      支付ID
     * @param paymentType 支付类型
     * @throws Exception e
     */
    @Transactional
    public Map<String, Object> didPayment(String pay_id, String paymentType) throws Exception {
        Map<String, Object> result = new HashMap<>();
        String payMent = "error";
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("billNo", pay_id);
        int billCount = 0;
        billCount = fundFlowBiz.findEntityCountBySql("select 1 from T_BIZ_FUND_FLOW where BILL_NO=:billNo", parameters);
        /**
         * fix支付漏洞，确保银行转账已到账，或者余额扣款成功
         */
        if (paymentABCBiz.queryABCPayStatus(pay_id) || billCount > 0) {
            result.put("payMent", "payMent");
            return result;
        }

        // 获取报关订单的信息
        List<DeclarationFree> declarationFrees = declarationFreeBiz.findFeeByPayId(pay_id);
        if (CollectionUtils.isNotEmpty(declarationFrees)) {
            DeclarationFree free = declarationFrees.get(0);
            if ("2".equals(paymentType)) {
                Company userCompany = LoginUtil.getLoginUser().getCompany();
                double balance = fundFlowBiz.findCurrentBalance(userCompany.getId());
                if (balance < Double.parseDouble(free.getSum_free())) {
                    payMent = "balance_error";
                } else {
                    fundFlowBiz.addPayFlow(userCompany, Double.parseDouble(free.getSum_free()), FundIETypeEnum.DC_PAY, pay_id, free.getDeclaration().getSupCompany());
                    payMent = "success";
                    // Integer id = null;
                    // int i = 100;
                    // int val = i / id;
                    // System.out.println("测试中");
                }
            } else {
                // 生成支付请求 根据支付请求
                // 根据支付请求的结果，跳转支付页面 free.getSum_free()
                // free.setSum_free("0.1");
                Map<String, String> paymentRequestResult = paymentABCBiz.requestForPayment(free.getPay_id(), free.getSum_free(), "报关单费用", paymentType);
                if (paymentRequestResult != null && KEY_request_result_success.endsWith(paymentRequestResult.get(KEY_request_result))) {
                    payMent = paymentRequestResult.get(KEY_paymentURL);
                } else {
                    payMent = "error";
                }
            }
            if ("success".equals(payMent)) {
                List<String> declaration_ids = new ArrayList<String>();
                for (DeclarationFree free1 : declarationFrees) {
                    String declarationId = free1.getDeclaration().getId();
                    updatePayState(declarationId);
                    chargingService.customerDidPay(declarationId);
                    free.setPay_comfirm("1");
                    free.setPay_time(new Date());
                    declarationFreeBiz.saveOrupdateEntity(free);
                    declaration_ids.add(free.getDeclaration().getId());
                    if (free.getFree() != null && !"".equals(free.getFree())) {
                        if ("0.0".equals(free.getFree()) || "0".equals(free.getFree())) {
                            this.updatePaymentType(free.getDeclaration().getId(), "2");
                        } else {
                            this.updatePaymentType(free.getDeclaration().getId(), "1");
                        }
                    }
                    logger.info("支付成功，订单的pay_id ==" + pay_id);
                    logger.info("订单的 订单号：" + free.getDeclaration().getId());
                }
                String payFree = declarationFrees.get(0).getSum_free();
                this.bizConfirm(declaration_ids.toArray(new String[0]));
            }
        } else {
            payMent = "error";
        }
        result.put("payMent", payMent);
        // 2017-01-08由dengdc加入下面的处理逻辑，处理error时候的数据回滚
        // 只要payMent的值不是success,则抛出异常并放弃本次支付
        if (!"success".equals(payMent)) {
            throw new Exception(payMent);
        }
        // 结束
        return result;
    }

    /**
     * 根据报关单ID，将对应的报关单上传至电子口岸
     */
    public void uploadToCargoDeclaration(String declarationId) throws Exception {
        cargoDeclarationHelper.didUpload(declarationId);
    }

    /**
     * 根据公司id，单证录入时间查找所有的报关单
     *
     * @param companyId 公司id
     * @param dateStr   单证录入时间，
     * @param pattern   时间格式，默认：YYYYMM
     */
    public List<Declaration> findByCompanyMonth(String companyId, String dateStr, String pattern) throws Exception {
        if (StringUtils.isEmpty(pattern)) {
            pattern = "yyyymm";
        }
        String hql = "select Declaration from com.mrd.gtimp.business.entity.Declaration Declaration where to_date(to_char(Declaration.ctime,'" + pattern + "'),'" + pattern + "') = to_date('" + dateStr + "','" + pattern + "') and  Declaration.customer.id='" + companyId + "'";
        List<Declaration> list = this.findEntityByHql(hql, 0, 0, null);
        List<DeclarationFreeDetail> declarationFreeDetails = declarationFreeDetailBiz.findAllEntity();
        list = declarationFreeBiz.countFree(list, declarationFreeDetails);
        return list;
    }


    /**
     * 根据公司ID，柜号，报关单号查找报关单
     *
     * @param companyId   公司ID
     * @param containerNo 柜号
     * @param sno         报关单号
     */
    public List<Declaration> findByCompanyContainerNoSno(String companyId, String containerNo, String sno) {
        if (StringUtils.isEmpty(companyId) && StringUtils.isEmpty(containerNo) && StringUtils.isEmpty(sno)) {
            return null;
        }
        String hql = "select Declaration from com.mrd.gtimp.business.entity.Declaration Declaration where Declaration.customer.id='" + companyId + "'";
        if (StringUtils.isNotEmpty(containerNo)) {
            hql += " and Declaration.container_no = '" + containerNo + "' ";
        }
        if (StringUtils.isNotEmpty(sno)) {
            hql += " and Declaration.sno = '" + sno + "'";
        }
        List<Declaration> list = this.findEntityByHql(hql, 0, 0, null);
        return list;
    }


    /**
     * 更新订单第二供应商
     *
     * @author han
     */
    @Transactional
    public void updateSecondSup(Declaration declaration) throws Exception {
        BaseBusiness rtnBusines = businessBiz.findEntityById(declaration.getId());
        rtnBusines.setSecondSupId(declaration.getSecondSupId());
        rtnBusines.setSecondSupIdCode(declaration.getSecondSupIdCode());
        businessBiz.saveOrupdateEntity(rtnBusines);
    }

    public Declaration rejectToNew(Declaration declaration, String rejectCount) {
        declaration.setId(null);
        declaration.setBusinessId(declaration.getBusinessId() + rejectCount);
        declaration.setInspectionGoodsList(null);
        declaration.setDeclarationInform(null);
        declaration.setContractTerms(null);
        declaration.setRejectContents(null);
        if (declaration.getCommodities() != null) {
            declaration.getCommodities().forEach(x -> x.setId(null));
        }
        if (declaration.getDeclaContainers() != null) {
            declaration.getDeclaContainers().forEach(x -> x.setId(null));
        }
        if (declaration.getSuiFuDans() != null) {
            declaration.getSuiFuDans().forEach(x -> x.setId(null));
        }
        return declaration;
    }

    @Transactional
    public void updateWorkNo(Declaration declaration) throws Exception {
        if (declaration == null || StringUtils.isEmpty(declaration.getId())) {
            throw new Exception("Declaration is null");
        }
        jdbcTemplate.update("update t_biz_base_business b set b.bpk=? where b.id=?", new Object[]{declaration.getBpk(), declaration.getId()});
        jdbcTemplate.update("update t_biz_declaration d set d.sno=?,d.contract_no=?,d.container_no=?,d.work_no=? where d.id=?", new Object[]{declaration.getSno(), declaration.getContract_no(), declaration.getContainer_no(), declaration.getWorkNo(), declaration.getId()});
    }


    /**
     * 同步数据到QP小工具
     *
     * @param did 报关单ID
     * @param fu  不知道是什么
     */
    public Result syncQPData(String did, String fu) throws Exception {
        final String did_ = did;
        final Declaration od = findEntityById(did_);
        if (od != null) {
            JdbcTemplate qpdataJdbctemplate = SpringUtils.getBean("qpdataJdbcTemplate", JdbcTemplate.class);
            if ("1".equals(fu) || od.getQpdrsj() == null || od.getQpscsj() == null) {
                // ---------------------------------------
                // ----------调用存储过程---------------
                // ---------------------------------------
                qpdataJdbctemplate.execute(con -> {
                    CallableStatement cs = con.prepareCall("{call getyxt_one(?)}");
                    cs.setString(1, od.getBusinessId());
                    return cs;
                }, (CallableStatementCallback<Object>) cs -> {
                    cs.execute();
                    return null;
                });
                // ------------------------------------------------------------------------
                excuteSql("update t_biz_base_business t set (qp_flag,qp_djzt,qp_ztsj,qp_tyno,qp_hgno,qpdrsj,qpscsj,qpdrzt) = (select null, null,null,null,null ,sysdate,null,null from dual) where id=:did", new HashMap<String, Object>() {
                    {
                        put("did", did_);
                    }
                });
            } else if (StringUtils.isNotBlank(od.getQptyno())) {
                // ---------------------------------------
                // ----------更新同步时间---------------
                // ---------------------------------------
                qpdataJdbctemplate.execute(con -> {
                    CallableStatement cs = con.prepareCall("update masterdata set ty_no=:qptyno where djbm=:bid");
                    cs.setString("bid", od.getBusinessId());
                    cs.setString("qptyno", od.getQptyno());
                    return cs;
                }, (CallableStatementCallback<Object>) cs -> {
                    cs.execute();
                    return null;
                });
                excuteSql("update t_biz_base_business t set (qp_flag,qp_djzt,qp_ztsj,qp_tyno,qp_hgno,qpdrsj) = (select '0', djzt,ztsj,ty_no,hg_no ,sysdate from qpdata.masterdata@QPDATA where djbm=t.business_id) where id=:did", new HashMap<String, Object>() {
                    {
                        put("did", did_);
                    }
                });
                String fgsno_head = "5189" + Calendar.getInstance().get(Calendar.YEAR);// "51892016"//test
                // by:
                // http://www.shucunwang.com/RunCode/java/
                excuteSql("update t_biz_declaration d set (sno) = (select case when qp_hgno is null then d.sno else case when sup_id = '402881e93cf50c90013cf51f40b60000' then substr(replace(qp_hgno,'" + fgsno_head + "',''),2,11) else qp_hgno end end hgno from t_biz_base_business b where b.id=d.id) where id=:did", new HashMap<String, Object>() {
                    {
                        put("did", did_);
                    }
                });
                excuteSql("update t_biz_declaration d set (state)=(select   case when d.state='DS05' then 'DS05' else  case when qp_djzt='通关无纸化放行' or qp_djzt='通关无纸化放行,转关单自动放行' then      CASE when d.state='DS11' then 'DS05' else 'DS10' end  ELSE      case when qp_djzt='通关无纸化查验' then 'DS09' else d.state end  end   end djzt  from t_biz_base_business b  where b.id=d.id) where d.id=:did", new HashMap<String, Object>() {
                    {
                        put("did", did_);
                    }
                });

            } else {
                dataLockUtil.releaseLock("VDBS", did);
                return Result.newFailInstance("需要强制同步");
            }
        }
        dataLockUtil.releaseLock("VDBS", did);
        return Result.newSuccessInstance("操作成功");
    }

    // Declaration declaration = declarationDao.getOne(did);
    public Declaration getOneDeclaration(String did) {
        return declarationDao.getOne(did);
    }


    /**
     * 确认三联单
     */
    @Transactional
    public void confirmSanLianDan(Declaration declaration) throws Exception {
        CtmsServiceClient client = new CtmsServiceClient();
        String reqUserAccount = declaration.getModifier();
        String reqUserName = null;
        if(StringUtils.isEmpty(reqUserAccount)){
            reqUserAccount = declaration.getCreator();
        }
        if(StringUtils.isNotEmpty(reqUserAccount)){
            reqUserName = userDao.findByAccount(reqUserAccount).getName();
        }
        try {
            String result = client.sendBGInfo(declaration, reqUserName);
            if (StringUtils.isNotEmpty(result)) {
                JSONObject jsonObject = JSON.parseObject(result);
                String msg = jsonObject.getString("msg");
                String workNo = jsonObject.getString("workNo");
                if (StringUtils.isNotEmpty(msg) && StringUtils.isNotEmpty(workNo) && msg.equals("1")) {
                    declaration.setConfirmTypeTime(new Date());
                    declaration.setWorkNo(workNo);
                    declaration.setWork_no(workNo);

                    List<String> properties = new ArrayList<>();
                    properties.add("confirmType");
                    properties.add("confirmTypeTime");
                    properties.add("work_no");
                    properties.add("workNo");
                    this.updateEntity(declaration, properties);
                } else {
                    throw new Exception("推送报关单失败");
                }
            } else {
                throw new Exception("推送报关单失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("推送报关单失败");
        }
    }

    /**
     * 获取驳船信息
     *
     * @param id 报关单id
     */
    public CTMSShipInfoDTO getShipInfo(String id) {
        CtmsServiceClient client = null;
        try {
            client = new CtmsServiceClient();
            String result = client.getShipInfo(id);
            //{"blNo":"EL170808121","ciqNo":"5180550059","ePort":"51890","reqNo":"111","shipName":"鸿安泰333","transportName":"5200550202","voyageNo":"170815000000"}
            //result = "{\"blNo\":\"EL170808121\",\"ciqNo\":\"5180550059\",\"ePort\":\"51890\",\"reqNo\":\"111\",\"shipName\":\"鸿安泰333\",\"transportName\":\"5200550202\",\"voyageNo\":\"170815000000\"}";
            if (StringUtils.isEmpty(result) || result.equals("2") || result.equals("3")) {
                return null;
            }
            CTMSShipInfoDTO dto = JSONObject.toJavaObject(JSONObject.parseObject(result), CTMSShipInfoDTO.class);
            return dto;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 批量获取驳船信息
     *
     * @param ids 报关单id
     */
    public Result getShipInfos(String[] ids) {
        for (String id : ids) {
            if (StringUtils.isEmpty(id)) {
                continue;
            }
            try {
                Declaration declaration = this.findEntityById(id);
                //只有在已受理状态才允许获取
                if (Declaration.DeclarationBusinessState.PASS_STATE.equals(declaration.getState()) || Declaration.DeclarationBusinessState.ACCEPT_STATE.equals(declaration.getState())) {
                    CTMSShipInfoDTO dto = this.getShipInfo(id);
                    if (dto != null) {
                        declaration.setShip_name(dto.getShipName());// 船名
                        declaration.setShip_code(dto.getShipCode());// 船舶代码
                        //                        declaration.setExport_port(dto.getePort());// 出口口岸
                        if ("直航".equals(declaration.getData_type())){
                            declaration.setTransport_na(dto.getShipCode());// 运输工具名称
                        }
                        declaration.setVoyage_no(dto.getVoyageNo());// 航次号
                        declaration.setBl_no(dto.getBlNo());// 提运单号
                        this.saveOrupdateEntity(declaration);
                    }
                }
            } catch (QueryException e) {
                e.printStackTrace();
            } catch (SaveException e) {
                e.printStackTrace();
            }
        }
        return Result.newSuccessInstance("操作完成");
    }

    /**
     * 获取联系方式
     */
    public Result getContactWay(String did, String role) {
        com.mrd.gtimpframe.entity.User user = userMapper.selectByDidAndRole(did, role);
        if (user == null) {
            return Result.newFailInstance("没有该用户的信息");
        }
        return Result.newSuccessInstance("查询成功", user);
    }

    public Result bizConfirm(String[] declaration_ids) {
        Result msg;
        List<Declaration> declarations = null;
        if (ArrayUtils.isEmpty(declaration_ids)) {
            return Result.newFailInstance(MsgConstants.OPERATION_FAIL);
        }
        try {
            String hql = "select t.id,t.state from com.mrd.gtimp.business.entity.Declaration t where t.id in (";
            for (String i : declaration_ids) {
                hql += "'" + i + "',";
            }
            hql = hql.substring(0, hql.lastIndexOf(","));
            hql += ")";
            System.out.println("sql:" + hql);
            List<Object> objList = this.findObjectByHql(hql, 0, 50, null);
            if (null != objList && objList.size() > 0) {
                declarations = new ArrayList<Declaration>();
                for (Object o : objList) {
                    Declaration b = new Declaration();
                    Object[] obj = (Object[]) o;
                    b.setId(obj[0].toString());
                    b.setDecState(obj[1].toString());
                    declarations.add(b);
                }
            }
            for (Declaration declare : declarations) {
                if (declare.getDecState().equals(BaseTypeConstant.DECLARATIONSTATE_00) || declare.getDecState().equals(BaseTypeConstant.DECLARATIONSTATE_03)) {
                    System.out.println("执行提交订单前id========" + declare.getId());
                    System.out.println("执行提交订单前状态========" + declare.getDecState());
                    this.updateBizConfirm(declare.getId());
                    // 邮件发送
                    /*
                     * String user_email = LoginUtil.getLoginUser().getEmail(); if(user_email != null) {
                     * String body = "您已下单成功，业务编号为：" + businessId; SendEmail.sendEmail(user_email, "货运平台下单通知",
                     * body); }
                     */
                }
            }

            msg = Result.newSuccessInstance(MsgConstants.OPERATION_SUCCESS);
            // else {
            // msg =Result.newFailInstance( MsgConstants.OPERATION_FAIL);
            // }
        } catch (Exception e) {
            msg = Result.newFailInstance(MsgConstants.OPERATION_FAIL);
            e.printStackTrace();
        }
        return msg;
    }
}
